在一切的開始之前,我想就先從「微服務」的定義開始,這樣後續在講這個議題的時候比較能聚焦。當然,這或許不是最正確的答案,但這是我目前以來認為「微服務」的樣子,在從事這些專案的過程,我也不斷地修正我自己對於微服務架構的定義,所以這可能不是最終版,而是我現在的認知。
通常在一個專案開始之前,我會問問客戶他們覺得微服務是什麼?想透過微服務來達到什麼目的?很多時候,我會得到許多不同的答案。所以,在開始一切的工作之前,我們應該先釐清楚現在討論的議題是什麼。
如果我們在會議室裡問十個人「什麼是微服務?」,大概會得到十個不同版本的答案。這其實不奇怪,因為微服務並沒有唯一的權威定義。但在眾多專家與實務經驗的累積中,有幾個共同點逐漸浮現出來。
如同前一天文章所述,微服務可以這樣被定義:
微服務是一種將應用程式設計為一組小型、自治、鬆散耦合服務的架構風格,每個服務對應到一個獨立的業務能力,並且透過清晰的 API 來彼此協作。
所以,微服務就是由上面的概念所組成,在這個時候我們還不討論什麼 Clean Architecture 這些事情,反正先想辦法讓自己的「服務元件」具備上述特性,就先擦到邊了(一下子想太多,就會覺得很難不想做,所以先講一下最小的範疇)!
在服務拆解的時候,或許我們不需要那麼嚴肅,就先從「模組化」這件事開始好了,模組化做到某個程度就可以套入上述定義。
而我在投影片上常跟客戶解釋的是:
微服務是圍繞業務領域塑模而成,可獨立發布的服務。
(但好像會有一些只有「技術」,沒有業務的情境,那之後等 DDD 的篇章再來交代)....
在討論微服務的時候,我們通常會把它定義成一種「架構風格」。那什麼是「架構」?
在這詞似乎源自於建築業,但在這裡我就不深究這些歷史,簡單來說,「架構」就是協助我們滿足軟體設計上「非功能性」需求的一種模式。
舉例來說:
你正在負責開發一個企業核心業務系統。這個系統對公司極為重要,因為它直接支撐了公司在市場上的競爭力。你需要能夠快速、頻繁、可靠地交付改變,才能讓企業在今天這個 VUCA(易變、不確定、複雜、模糊) 的環境裡存活下來。
那這裡提到的「快速、頻繁、可靠地交付改變」就是我們指的「非功能性」需求,他跟業務功能沒有直接的關係。為了滿足這個「非功能性」需求,每個團隊透過 DevOps 實踐來交付軟體,包括自動化測試、持續交付(Continuous Deployment)、持續監控(Continuous Monitoring)。團隊不再是一季交付一大包需求,而是以一連串小而頻繁的變更(small, frequent changes)持續推向生產環境。讓我們的軟體可以輔助實現這些概念就是一種「架構」的實現。
如果你到 Google 搜尋,「微服務架構」通常你都會看到下列這張圖。
所以,從這張圖上可以簡單得到一個解釋是「微服務架構」是將原本一個「業務活動」拆解成多個服務元件模組,透過這些元件的協作共同完成這個業務活動。這上面的「服務元件」彼此可以獨立運作,獨立部署 (世界沒有那麼美好,還有很多耦合的問題需要處理)。
在這樣的架構下,每個團隊負責一個或數個子領域(Subdomain)。所謂子領域,就是一個可實作的業務功能切片(business capability)。它包含:
舉例來說,一個以 Java 建立的子領域可能包含一組程式碼(package),最後被編譯成一個 JAR 或 WAR,並以容器形式獨立部署。
關於「通訊介面」就是微服務的另外一個重心,那是服務元件與服務元件之間溝通的主軸:
微服務架構的特色就是讓每個子領域在技術與組織層面上都保持相對獨立,這樣一來,系統可以隨著業務需求快速演進,而不會陷入「大系統卡住誰也動不了」的窘境。
為了讓這個概念更直觀,我來舉一個例子(這是很多書上會舉的案例)。假設我們要開發一個線上書店系統。
在單體式架構下,我們可能會有一個大型應用程式,裡面包含:
這些模組都在同一個程式,部署成一個應用。只要有任何模組需要更新(例如支付模組需要支援新的金流),就必須重新編譯、測試並重新部署整個系統。即便只是修改一個支付 API,也可能牽動會員或訂單模組的測試,導致更新速度緩慢。
如果採用微服務設計,我們會把這些模組切分成不同的服務:
每個服務都有自己的資料庫與 API,能獨立開發與部署。例如支付服務要加入新的金流方式,只需更新支付服務( Payment Service) 並重新部署,不會影響到其他三個服務模組。
在這一篇我提出了一個我目前認定的「微服務」定義,後續我們會以這個定義進行後續討論。接著,我想開始談談「微服務設計的模式」(Microservice Architecture Patterns),透過這個 Pattern 的指引來協助團隊建立一個微服務導入的地圖,知道在這條路上前輩們遇過哪些問題,現階段有哪些的解決方案等。